﻿#region Copyright © 2009, DevExpressContrib (MIT License)
// This software is licensed under The MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#endregion

namespace DevExpressContrib.Core.Ux
{
    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Net.Mail;
    using System.Net.NetworkInformation;
    using DevExpressContrib.Core.Interface;

    /// <summary>
    /// Implements the ISendExceptionEmail to use SMTP to send the email.
    /// </summary>
    public class SmtpExceptionEmail : ISendExceptionEmail
    {
        private List<Attachment> attachments = new List<Attachment>();

        /// <summary>
        /// Initializes a new instance of the <see cref="SmtpExceptionEmail"/> class.
        /// </summary>
        /// <param name="host">The SMTP host address.</param>
        /// <param name="toEmailAddress">The to email address.</param>
        /// <param name="username">The SMTP credentials username.</param>
        /// <param name="password">The SMTP credentials password.</param>
        public SmtpExceptionEmail(string host, string toEmailAddress, string username, string password)
        {
            GuardAgainst.ArgumentIsNullOrEmpty(host, "host");
            GuardAgainst.ArgumentIsNullOrEmpty(toEmailAddress, "toEmailAddress");

            ToEmailAddress = toEmailAddress.Trim();
            if (!EmailHelper.IsEmailAddressWellFormed(toEmailAddress))
                throw new InvalidOperationException(String.Format("The toEmailAddress: {0} is not well formed.", toEmailAddress));
            Host = host.Trim();
            Username = username;
            Password = password;
            EnableSsl = false;
            Port = 25;
        }

        /// <summary>
        /// Gets the list of email attachments.
        /// </summary>
        /// <value>The list of email attachments.</value>
        public List<Attachment> Attachments
        {
            get { return attachments; }
        }

        /// <summary>
        /// Gets or sets the body of the email.
        /// </summary>
        /// <value>The body of the email.</value>
        public string Body { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether SSL should be enabled.
        /// </summary>
        /// <value><c>true</c> if SSL should be enabled; otherwise, <c>false</c>.</value>
        public bool EnableSsl { get; set; }

        /// <summary>
        /// Gets or sets 'From' email address.
        /// </summary>
        /// <value>The 'From' email address.</value>
        public string FromEmailAddress { get; set; }

        /// <summary>
        /// Gets or sets the SMTP host.
        /// </summary>
        /// <value>The SMTP host.</value>
        public string Host { get; private set; }

        /// <summary>
        /// Gets or sets the SMTP credentials password.
        /// </summary>
        /// <value>The SMTP SMTP credentials password.</value>
        public string Password { get; private set; }

        /// <summary>
        /// Gets or sets the SMTP host port.
        /// </summary>
        /// <value>The SMTP host port.</value>
        public int Port { get; set; }

        /// <summary>
        /// Gets or sets the email subject line.
        /// </summary>
        /// <value>The email subject line.</value>
        public string Subject { get; set; }

        /// <summary>
        /// Gets or sets the to email address.
        /// </summary>
        /// <value>The to email address.</value>
        public string ToEmailAddress { get; private set; }

        /// <summary>
        /// Gets or sets the SMTP credentials username.
        /// </summary>
        /// <value>The SMTP credentials username.</value>
        public string Username { get; private set; }


        /// <summary>
        /// Determines whether this instance can send email with the current properties.
        /// </summary>
        /// <returns>
        /// 	<c>true</c> if this instance can send email; otherwise, <c>false</c>.
        /// </returns>
        public bool CanSendEmail()
        {
            bool result;
            if (Host == null || ToEmailAddress == null)
                return false;
            else
                result = !String.IsNullOrEmpty(Host.Trim()) && !String.IsNullOrEmpty(ToEmailAddress.Trim());

            if (result)
            {
                using (Ping ping = new Ping())
                {
                    PingReply reply = ping.Send(Host);
                    result = (reply.Status == IPStatus.Success);
                }
            }
            return result;
        }

        /// <summary>
        /// Sends the email with the current property values.
        /// </summary>
        /// <param name="errorMessage">An error message about why the email could not be sent.</param>
        /// <returns>
        /// 	<c>true</c> if the email could be sent; otherwise, <c>false</c>.
        /// </returns>
        public bool SendEmail(out string errorMessage)
        {
            errorMessage = String.Empty;
            bool result = false;

            if (!CanSendEmail())
            {
                errorMessage = "Could not connect to SMTP server.";
            }
            else
            {
                using (MailMessage mail = new MailMessage())
                {
                    foreach (Attachment item in Attachments)
                    {
                        mail.Attachments.Add(item);
                    }

                    if (String.IsNullOrEmpty(FromEmailAddress))
                        mail.From = new MailAddress(ToEmailAddress);
                    else
                        mail.From = new MailAddress(FromEmailAddress);
                    mail.To.Add(ToEmailAddress.Trim());
                    mail.Subject = Subject;
                    mail.BodyEncoding = System.Text.Encoding.UTF8;
                    mail.Body = Body;
                    SmtpClient client = new SmtpClient();
                    if (!String.IsNullOrEmpty(Username) && !String.IsNullOrEmpty(Password))
                    {
                        client.Credentials = new NetworkCredential(Username, Password);
                    }
                    client.Host = Host.Trim();
                    client.Port = Port;
                    client.EnableSsl = EnableSsl;
                    try
                    {
                        client.Send(mail);
                        result = true;
                    }
                    catch (Exception exception)
                    {
                        // Catch everything and return false. The caller should be logging this issue.
                        errorMessage = exception.Message;
                    }
                }
            }
            return result;
        }
    }
}
